Skip to content

feat: instant-paint boot loading bar - #14

Merged
DecodedXR merged 1 commit into
mainfrom
feat/boot-loading-bar
Jul 4, 2026
Merged

DecodedXR merged 1 commit into
mainfrom
feat/boot-loading-bar

Conversation

@DecodedXR

Copy link
Copy Markdown
Owner

What & why

User-directed polish: make the page load faster + a nice loading bar that starts when you open the page.

Today the app is a blank black screen until the ~194 KB-gzipped entry bundle (essentially all Three.js) downloads, parses, and renders the first frame — zero feedback. This adds an inline, instant-paint boot loading bar.

  • The overlay + its critical CSS live directly in index.html (a <head> <style> + #boot-loader markup). Vite passes both through untouched into the built HTML, ahead of the module <script>, so the bar paints on the first paint — before any JS downloads.
  • The fill advances toward 92% on a pure-CSS animation; src/main.js snaps it to 100% and fades the overlay out on the first rendered frame (a one-shot after the first renderer.render in animate()).
  • animate() runs synchronously at module eval, before window.__app is assigned — so the overlay is already pointer-events:none / removed before any UI interaction, and it never covers #controls.

Honest scope on "faster"

This is a perceived-load win (First Contentful Paint: blank → instant + progress feedback). The JS payload is unchanged — Three.js is required to render the first frame, and the depth model already lazy-loads (transformers.web, the ORT wasm, and depth-worker are all separate on-demand chunks; no model bytes at boot). Shrinking Three.js / touching deps / build / CI config is out of scope per CLAUDE.md + STATUS.md, so I did not fabricate a bundle-size reduction.

RED test (non-tautological)

New tests/smoke.spec.js test asserts, together:

  1. the loader ships in the raw server HTML — fetched via page.request.get('/'), so a JS-injected node can't satisfy it (proves it's up before JS);
  2. the loader is gone once window.__app is ready (proves main.js dismisses it).

Proven non-tautological: baseline (no loader) is RED on (1); an intermediate build with the loader in HTML but dismissal disabled was verified RED on (2) — the overlay stayed visible for all retries.

Full local suite: 14/14 green (npm test, real Chromium + software WebGL).

Independent adversarial verification

A separate read-only verifier (no access to my reasoning) could not refute the change. It confirmed the load-bearing safety property — dismissal is synchronous in the first animate() call, before __app is set and before any test interacts, so the overlay can never intercept clicks on the control UI the other 13 tests drive. Two cosmetic nits only, both "not blockers, not regressions": a frozen bar on an already-broken boot path (a cosmetic improvement over today's black page; never affects a working app), and role="progressbar" without aria-valuenow (valid ARIA — omitted valuenow signals indeterminate).

Review

/code-review here launches a billed cloud Workflow; autopilot mandates local/not-billed unless opted in, so the diff was reviewed inline (+ the adversarial verifier above). No unresolved or judgment-call findings.

Visual check

Verified on a real production build — frozen-loader screenshot shows the centered "LIVE DEPTH FIELD" title + a blue gradient fill (~92%) with a soft glow on the black background, matching the app's splat aesthetic.

Rollback

Pre-change HEAD: 789d6ae89cdead41dd48a40175676b00527fc32b

🤖 Generated with Claude Code

The app showed a blank black screen until the ~194KB-gzipped entry bundle
(Three.js) downloaded, parsed, and rendered the first frame — no feedback.

Add an inline boot loader: an overlay + critical CSS live directly in
index.html (a <head> <style> + #boot-loader markup Vite passes through into
the built HTML ahead of the module <script>), so the loading bar paints on
the FIRST paint, before any JS downloads. The fill advances toward 92% on a
pure-CSS animation; src/main.js snaps it to 100% and fades the overlay out
on the first rendered frame (a one-shot after the first renderer.render in
animate(), which runs synchronously at module eval — before window.__app is
set, so the overlay is pointer-events:none/removed before any UI interaction).

This is a perceived-load win (First Contentful Paint: blank -> instant). The
JS payload is unchanged: Three.js is required for the first frame and the
depth model already lazy-loads (no model bytes at boot).

Smoke test asserts the loader ships in the raw server HTML (fetched via
page.request.get('/'), so a JS-injected node can't satisfy it) AND is gone
once the app boots — non-tautological only together.

Autopilot: user-directed polish (boot loading bar)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@DecodedXR
DecodedXR merged commit d455809 into main Jul 4, 2026
2 checks passed
@DecodedXR
DecodedXR deleted the feat/boot-loading-bar branch July 4, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant